/*
 * DictionaryTermsFile_test.cpp
 *
 *  Created on: Oct 12, 2012
 *      Author: m
 */

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cassert>
#include <cstdlib>
#include <sstream>
#include "DictionaryTermsFile.h"
#include "tools/Heap.h"
#include "ExternalSort.h"

#define _LINE_BUFFER_SIZE 40
#define _LONG_SERIALIZATION_ARG  "-l"
#define _SHORT_SERIALIZATION_ARG "-s"
#define _TO_BIN_MODE_ARG "-tobin"
#define _TO_TXT_MODE_ARG "-totxt"

using namespace std;

template<typename T>
void printArray(T array[], size_t size) {
	for (size_t i = 0; i < size; i++) {
		cout << array[i] << " ";
	}
	cout << endl;
}

int comparator(int i1, int i2) {
	return i1 - i2;
}

void assertAndPrintPoppedItems(Heap<int, comparator> &heap, int expected[]) {
	size_t heapCount = heap.lenght();
	for (size_t i = 0; i < heapCount; i++) {
		int reg = heap.popItem();
		cout << reg << " ";
		assert(reg == expected[i]);
	}
	cout << endl;
}

void assertAndPrintItems(unsigned int i, int expected[], int reg) {
	cout << reg << " ";
	assert(reg == expected[i]);
}

int main(int argc, char* argv[]) {

	try {

		cout << "___Heap Test___" << endl;

		int input[] = { 10, 56, 2, 7, 6, 4, 12 };

		printArray(input, 7);

		cout << "Pop Test" << endl;
		{
			Heap<int, comparator> heap(7);
			int expected[] = { 2, 4, 6, 7, 10, 12, 56 };

			for (size_t i = 0; i < 7; i++) {
				heap.loadItem(input[i]);
			}

			heap.heapify();
			cout << "Output:" << endl;

			assertAndPrintPoppedItems(heap, expected);
		}

		cout << "PushAndPop Test" << endl;
		{
			Heap<int, comparator> heap(7);
			int reg = -1;
			for (size_t i = 0; i < 4; i++) {
				heap.loadItem(input[i]);
			}
			heap.heapify();
			cout << "Output:" << endl;
			{
				int expected[] = { 2, 6 };
				for (size_t i = 4; i < 6; i++) {
					reg = heap.pushAndPopItem(input[i]);
					assertAndPrintItems(i - 4, expected, reg);
				}
			}
			cout << "Rest:" << endl;
			{
				int expected[] = { 4, 7, 10, 56 };
				assertAndPrintPoppedItems(heap, expected);
			}
		}

		cout << "Freeze Test" << endl;
		{
			Heap<int, comparator> heap(3);
			int reg = -1;
			for (size_t i = 0; i < 3; i++) {
				heap.loadItem(input[i]);
			}
			heap.heapify();
			cout << "Output Freeze:" << endl;
			{
				int expected[] = { 2, 10, 56 };
				for (size_t i = 3; i < 6; i++) {
					reg = heap.freezeItem(input[i]);
					assertAndPrintItems(i - 3, expected, reg);
				}
			}
			cout << endl << "UnFreezed Items:" << endl;
			{
				int expected[] = { 4, 6, 7 };
				heap.unfreezeItems();
				assertAndPrintPoppedItems(heap, expected);
			}
		}

		cout << "___External Sort Test___" << endl;
		{
			string testInput = "testFile.bin";
			string testOutput = "./particiones/Temp_3";
			string testOutput2 = "./outputFile";
			size_t bufferSize = 100;
			DictionaryTermsFile dictionaryInput(testInput.c_str(),
					ios_base::out | ios_base::trunc, bufferSize, bufferSize,
					true);

			for (int i = 1; i <= 1000; i++) {
				std::stringstream numberComverter;

				numberComverter << i;

				DictionaryTerm* term = new DictionaryTerm((std::string("test") + numberComverter.str()).c_str(), (i * 37 + i) % 10,
						i);
				dictionaryInput.put(term);
			}

			dictionaryInput.close();

			dictionaryInput.open(testInput.c_str(), std::ios_base::in);

			cout << "Sort Input:" << endl;
			while (dictionaryInput.hasNext()) {
				std::shared_ptr<DictionaryTerm> term = dictionaryInput.get();
				cout << term->getTerm() << ":" << term->getRandomKey() << " ";
			}

			dictionaryInput.close();

			ExternalSort sorter(1, testInput);
			sorter.sort();

			cout << endl << "Sort Heap Output:" << endl;
			DictionaryTermsFile dictionaryOutput(testOutput.c_str(),
					ios_base::in, bufferSize, bufferSize, true);

			int count = 0;
			while (dictionaryOutput.hasNext()) {
				count++;
				std::shared_ptr<DictionaryTerm> term = dictionaryOutput.get();
				cout << term->getTerm() << ":" << term->getRandomKey() << " ";
			}
			cout << endl << "Sort Output:" << endl;
			DictionaryTermsFile dictionaryOutput2(testOutput2.c_str(),
					ios_base::in, bufferSize, bufferSize, true);

			int count2 = 0;
			while (dictionaryOutput2.hasNext()) {
				count2++;
				std::shared_ptr<DictionaryTerm> term = dictionaryOutput2.get();
				cout << term->getTerm() << ":" << term->getRandomKey() << " ";
			}

			dictionaryOutput.close();
			dictionaryOutput2.close();

			cout<<endl<<"cantidad salida:"<<count<<endl;
		cout<<endl<<"cantidad salida2:"<<count2<<endl;

		}

	} catch (string *e) {
		cout << "\n\n----------------\nException Thrown:" << *e
				<< "\n----------------\n\n";
		delete e;
	}

	return 0;
}
